#include "map_service.h"
#include <QFile>
#include <QDir>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QCoreApplication>
#include <QDebug>

namespace infrastructure {

MapService::MapService(kernel::ILogger* logger, QObject* parent)
    : QObject(parent)
    , m_logger(logger)
{
}

kernel::Result<std::shared_ptr<kernel::Map>> MapService::loadMapFromFile(const QString& filePath) {
    try {
        QString fullPath = filePath;

        // Check if it's an absolute path that exists
        if (QFileInfo(fullPath).isAbsolute()) {
            // For absolute paths, use as-is
            if (!QFile::exists(fullPath)) {
                QString error = QString("地图文件不存在: %1").arg(fullPath);
                if (m_logger) {
                    m_logger->error(error);
                }
                emit mapLoadFailed(error);
                return kernel::Result<std::shared_ptr<kernel::Map>>::failure(kernel::ErrorCode::FileNotFound, error);
            }
        } else {
            // Handle relative paths - look in maps directory
            QString mapsDir = QCoreApplication::applicationDirPath() + "/maps";
            QDir dir;
            if (!dir.exists(mapsDir)) {
                dir.mkpath(mapsDir);
            }

            QString filename = filePath;
            if (!filename.endsWith(".smap")) {
                filename += ".smap";
            }
            fullPath = mapsDir + "/" + filename;

            if (!QFile::exists(fullPath)) {
                QString error = QString("地图文件不存在: %1").arg(fullPath);
                if (m_logger) {
                    m_logger->error(error);
                }
                emit mapLoadFailed(error);
                return kernel::Result<std::shared_ptr<kernel::Map>>::failure(kernel::ErrorCode::FileNotFound, error);
            }
        }

        QFile file(fullPath);
        if (!file.open(QIODevice::ReadOnly)) {
            QString error = QString("Cannot open map file: %1").arg(fullPath);
            if (m_logger) {
                m_logger->error(error);
            }
            emit mapLoadFailed(error);
            return kernel::Result<std::shared_ptr<kernel::Map>>::failure(kernel::ErrorCode::FileAccessDenied, error);
        }

        QByteArray data = file.readAll();
        file.close();

        QJsonParseError parseError;
        QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &parseError);

        if (parseError.error != QJsonParseError::NoError) {
            QString error = QString("JSON parse error: %1").arg(parseError.errorString());
            if (m_logger) {
                m_logger->error(error);
            }
            emit mapLoadFailed(error);
            return kernel::Result<std::shared_ptr<kernel::Map>>::failure(kernel::ErrorCode::DataCorrupted, error);
        }

        // 解析 JSON 并返回 Map 对象
        auto result = parseJsonMap(jsonDoc.object());
        if (result.isSuccess()) {
            if (m_logger) {
                m_logger->info(QString("成功加载地图: %1").arg(result.getValue()->getHeader().mapName));
            }
            emit mapLoadFinished();
            return result;
        } else {
            emit mapLoadFailed(result.getErrorMessage());
            return result;
        }

    } catch (const std::exception& e) {
        QString error = QString("Exception during map loading: %1").arg(e.what());
        if (m_logger) {
            m_logger->error(error);
        }
        emit mapLoadFailed(error);
        return kernel::Result<std::shared_ptr<kernel::Map>>::failure(kernel::ErrorCode::SystemError, error);
    }
}

kernel::Result<void> MapService::saveMapToFile(const QString& filePath, const kernel::Map& map) const {
    // Implementation for saving map - not implemented yet
    Q_UNUSED(filePath)
    Q_UNUSED(map)
    return kernel::Result<void>::failure(kernel::ErrorCode::NotImplemented, "Save functionality not implemented");
}

kernel::Result<std::shared_ptr<kernel::Map>> MapService::parseJsonMap(const QJsonObject& rootObj) {
    auto map = std::make_shared<kernel::Map>();

    try {
        // Parse header
        if (rootObj.contains("header")) {
            QJsonObject headerObj = rootObj.value("header").toObject();
            kernel::MapHeader header;
            header.mapType = headerObj.value("mapType").toString();
            header.mapName = headerObj.value("mapName").toString();

            if (headerObj.contains("minPos")) {
                header.minPos = parsePosition(headerObj.value("minPos").toObject());
            }
            if (headerObj.contains("maxPos")) {
                header.maxPos = parsePosition(headerObj.value("maxPos").toObject());
            }
            header.resolution = headerObj.value("resolution").toDouble(1.0);

            map->setHeader(header);
        }

        // Parse station points
        if (rootObj.contains("advancedPointList")) {
            QJsonArray pointArray = rootObj.value("advancedPointList").toArray();
            for (const auto& value : pointArray) {
                kernel::StationPoint point = parseStationPoint(value.toObject());
                map->addStationPoint(point);
            }
        }

        // Parse paths
        if (rootObj.contains("advancedCurveList")) {
            QJsonArray curveArray = rootObj.value("advancedCurveList").toArray();
            for (const auto& value : curveArray) {
                QJsonObject curveObj = value.toObject();
                QString className = curveObj.value("className").toString();

                if (className == "BezierPath" || className == "DegenerateBezier") {
                    kernel::BezierPath path = parseBezierPath(curveObj);
                    map->addBezierPath(path);
                } else if (className == "ArcPath") {
                    kernel::ArcPath path = parseArcPath(curveObj);
                    map->addArcPath(path);
                } else if (className == "StraightPath") {
                    kernel::StraightPath path = parseStraightPath(curveObj);
                    map->addStraightPath(path);
                }
            }
        }

        // Parse normal points
        if (rootObj.contains("normalPosList")) {
            QJsonArray normalArray = rootObj.value("normalPosList").toArray();
            for (const auto& value : normalArray) {
                kernel::Position pos = parsePosition(value.toObject());
                map->addNormalPoint(pos);
            }
        }

        // Parse areas
        if (rootObj.contains("advancedAreaList")) {
            QJsonArray areaArray = rootObj.value("advancedAreaList").toArray();
            for (const auto& value : areaArray) {
                QJsonObject areaObj = value.toObject();
                QString className = areaObj.value("className").toString();

                kernel::Area area = parseArea(areaObj);
                if (className == "AdvancedArea") {
                    map->addArea(area);
                } else if (className == "BlockArea") {
                    map->addBlockArea(area);
                }
            }
        }

        // Build indexes for fast lookup
        map->buildIndexes();

        return kernel::Result<std::shared_ptr<kernel::Map>>::success(map);

    } catch (const std::exception& e) {
        QString error = QString("Exception during JSON parsing: %1").arg(e.what());
        return kernel::Result<std::shared_ptr<kernel::Map>>::failure(kernel::ErrorCode::DataCorrupted, error);
    }
}

kernel::StationPoint MapService::parseStationPoint(const QJsonObject& pointObj) const {
    kernel::StationPoint point;

    point.className = pointObj.value("className").toString();
    point.instanceName = pointObj.value("instanceName").toString();
    point.position = parsePosition(pointObj.value("pos").toObject());
    point.direction = pointObj.value("dir").toDouble();

    // Parse properties array
    if (pointObj.contains("property")) {
        QJsonArray propArray = pointObj.value("property").toArray();
        if (!propArray.isEmpty()) {
            point.property = parseProperty(propArray.at(0).toObject());
        }
    }

    return point;
}

kernel::BezierPath MapService::parseBezierPath(const QJsonObject& pathObj) const {
    kernel::BezierPath path;

    path.className = pathObj.value("className").toString();
    path.instanceName = pathObj.value("instanceName").toString();

    // Parse start and end points
    if (pathObj.contains("startPos")) {
        QJsonObject startObj = pathObj.value("startPos").toObject();
        path.startPoint.instanceName = startObj.value("instanceName").toString();
        path.startPoint.position = parsePosition(startObj.value("pos").toObject());
    }

    if (pathObj.contains("endPos")) {
        QJsonObject endObj = pathObj.value("endPos").toObject();
        path.endPoint.instanceName = endObj.value("instanceName").toString();
        path.endPoint.position = parsePosition(endObj.value("pos").toObject());
    }

    // Parse control points
    if (pathObj.contains("controlPos1")) {
        path.controlPoint1 = parsePosition(pathObj.value("controlPos1").toObject());
    }
    if (pathObj.contains("controlPos2")) {
        path.controlPoint2 = parsePosition(pathObj.value("controlPos2").toObject());
    }

    // Parse properties
    if (pathObj.contains("property")) {
        QJsonArray propArray = pathObj.value("property").toArray();
        for (int i = 0; i < std::min(2, static_cast<int>(propArray.size())); ++i) {
            path.properties[i] = parseProperty(propArray.at(i).toObject());
        }
    }

    path.color = Qt::black; // Default color

    return path;
}

kernel::ArcPath MapService::parseArcPath(const QJsonObject& pathObj) const {
    kernel::ArcPath path;

    path.className = pathObj.value("className").toString();

    if (pathObj.contains("startPos")) {
        QJsonObject startObj = pathObj.value("startPos").toObject();
        path.startPoint.instanceName = startObj.value("instanceName").toString();
        path.startPoint.position = parsePosition(startObj.value("pos").toObject());
    }

    if (pathObj.contains("endPos")) {
        QJsonObject endObj = pathObj.value("endPos").toObject();
        path.endPoint.instanceName = endObj.value("instanceName").toString();
        path.endPoint.position = parsePosition(endObj.value("pos").toObject());
    }

    if (pathObj.contains("controlPos1")) {
        path.controlPoint = parsePosition(pathObj.value("controlPos1").toObject());
    }

    return path;
}

kernel::StraightPath MapService::parseStraightPath(const QJsonObject& pathObj) const {
    kernel::StraightPath path;

    path.className = pathObj.value("className").toString();
    path.instanceName = pathObj.value("instanceName").toString();

    if (pathObj.contains("startPos")) {
        QJsonObject startObj = pathObj.value("startPos").toObject();
        path.startPoint.instanceName = startObj.value("instanceName").toString();
        path.startPoint.position = parsePosition(startObj.value("pos").toObject());
    }

    if (pathObj.contains("endPos")) {
        QJsonObject endObj = pathObj.value("endPos").toObject();
        path.endPoint.instanceName = endObj.value("instanceName").toString();
        path.endPoint.position = parsePosition(endObj.value("pos").toObject());
    }

    return path;
}

kernel::Area MapService::parseArea(const QJsonObject& areaObj) const {
    kernel::Area area;

    area.className = areaObj.value("className").toString();
    area.instanceName = areaObj.value("instanceName").toString();

    if (areaObj.contains("posGroup")) {
        QJsonArray posArray = areaObj.value("posGroup").toArray();
        for (int i = 0; i < std::min(4, static_cast<int>(posArray.size())); ++i) {
            area.corners[i] = parsePosition(posArray.at(i).toObject());
        }
    }

    if (areaObj.contains("property")) {
        QJsonArray propArray = areaObj.value("property").toArray();
        for (int i = 0; i < std::min(2, static_cast<int>(propArray.size())); ++i) {
            area.properties[i] = parseProperty(propArray.at(i).toObject());
        }
    }

    return area;
}

kernel::MapProperty MapService::parseProperty(const QJsonObject& propObj) const {
    kernel::MapProperty prop;

    prop.key = propObj.value("key").toString();
    prop.type = propObj.value("type").toString();
    prop.value = propObj.value("value").toString();

    return prop;
}

kernel::Position MapService::parsePosition(const QJsonObject& posObj) const {
    kernel::Position pos;
    pos.x = posObj.value("x").toDouble();
    pos.y = posObj.value("y").toDouble();
    return pos;
}

} // namespace infrastructure
